package src

import (
	"strings"
	"sync"
	"time"

	"gitee.com/haifengat/goctp/v2"
	zd "gitee.com/haifengat/zorm-dm/v2"
	"github.com/sirupsen/logrus"
)

func startTrade() {
	trd = goctp.NewTradePro()
	logrus.Infof("trade:%s user:%s,pwd:%s,broker:%s,appid:%s,authcode:%s", tradeFront, investorID, password, brokerID, appID, authCode)

	trd.Trade.OnFrontDisconnected = func(nReason int) {
		isLogin = false
		logrus.Info("trade disconnected ", nReason)
		if nReason != 0 {
			releaseTrade()
		}
	}
	trd.OnRtnInstrumentStatus = func(pInstrumentStatus *goctp.CThostFtdcInstrumentStatusField) {
		instrumentStatus[pInstrumentStatus.InstrumentID.String()] = pInstrumentStatus.InstrumentStatus
	}

	trd.OnOrder = func(pOrder *goctp.CThostFtdcOrderField) {
		sseOrder(new(OrderField).FromCTP(*pOrder))
	}
	trd.OnTrade = func(pTrade *goctp.CThostFtdcTradeField) {
		sseTrade(new(TradeField).FromCTP(*pTrade))
	}
	for k := range instrumentStatus {
		delete(instrumentStatus, k)
	}

	logInfo, info := trd.Start(goctp.LoginConfig{
		Front:    tradeFront,
		Broker:   brokerID,
		UserID:   investorID,
		Password: password,
		AppID:    appID,
		AuthCode: authCode,
	})
	onLogin(&logInfo, &info)
}
func releaseTrade() {
	isLogin = false
	trd.Release()
}

func onLogin(login *goctp.CThostFtdcRspUserLoginField, info *goctp.CThostFtdcRspInfoField) {
	logrus.Infof("trade login info: %+v", info)
	if info.ErrorID == 7 { // 未初始化
		go func() {
			time.Sleep(1 * time.Minute) // 一分钟试一次
			trd.ReqUserLogin(password)
		}()
	} else if info.ErrorID != 0 {
		go releaseTrade()
	} else {
		isLogin = true
		actionDay = "" // 初始化
		instLastMin = sync.Map{}
		tradingDay = login.TradingDay.String()
		// minPushed = sync.Map{}
		// mapInstrumentStatus = sync.Map{} // 会导致收不到行情：登录事件时交易状态已更新
		// 初始化 actionday
		if t, err := time.Parse("20060102", tradingDay); err == nil {
			preDay, _ := rdb.HGet(ctxRedis, "tradingday", "curday").Result()
			if strings.Compare(preDay, tradingDay) != 0 {
				cntTicks = 0
				logrus.Infof("清仓数据: %s, 交易日: %s", preDay, tradingDay)
				rdb.FlushAll(ctxRedis)
				rdb.HSet(ctxRedis, "tradingday", "curday", tradingDay)
				// 保存合约信息
				insts := make([]map[string]any, 0)
				for k, v := range trd.Instruments {
					info := InstrumentField{
						InstrumentID:      k,
						InstrumentName:    v.InstrumentName.String(),
						ProductID:         v.ProductID.String(),
						ExchangeID:        ExchangeIDType(v.ExchangeID.String()),
						PriceTick:         float64(v.PriceTick),
						VolumeMultiple:    int(v.VolumeMultiple),
						UnderlyingInstrID: v.UnderlyingInstrID.String(),
						OptionsType:       v.OptionsType,
						OpenDate:          v.OpenDate.String(),
						ExpireDate:        v.ExpireDate.String(),
						ProductClass:      v.ProductClass,
					}
					info.InsertTime = DateTimeType(time.Now().Local().Format(time.DateTime))
					info.UpdateTime = DateTimeType(time.Now().Local().Format(time.DateTime))
					insts = append(insts, zd.StructToMap(ctxDAO, info, false, true))
					if len(insts) == 1000 {
						zd.UpdateAndInsert[InstrumentField](ctxDAO, insts...)
						insts = make([]map[string]any, 0)
					}
				}
				zd.UpdateAndInsert[InstrumentField](ctxDAO, insts...)
			} else if n, _ := zd.SelectCount[InstrumentField](ctxDAO, nil); n == 0 {
				// 保存合约信息
				insts := make([]map[string]any, 0)
				for k, v := range trd.Instruments {
					info := InstrumentField{
						InstrumentID:      k,
						InstrumentName:    v.InstrumentName.String(),
						ProductID:         v.ProductID.String(),
						ExchangeID:        ExchangeIDType(v.ExchangeID.String()),
						PriceTick:         float64(v.PriceTick),
						VolumeMultiple:    int(v.VolumeMultiple),
						UnderlyingInstrID: v.UnderlyingInstrID.String(),
						OptionsType:       v.OptionsType,
						OpenDate:          v.OpenDate.String(),
						ExpireDate:        v.ExpireDate.String(),
						ProductClass:      v.ProductClass,
					}
					info.InsertTime = DateTimeType(time.Now().Local().Format(time.DateTime))
					info.UpdateTime = DateTimeType(time.Now().Local().Format(time.DateTime))
					insts = append(insts, zd.StructToMap(ctxDAO, info, false, true))
					if len(insts) == 1000 {
						zd.UpdateAndInsert[InstrumentField](ctxDAO, insts...)
						insts = make([]map[string]any, 0)
					}
				}
				zd.UpdateAndInsert[InstrumentField](ctxDAO, insts...)
			}
			if t.Weekday() == time.Monday { // 周一
				actionDay = t.AddDate(0, 0, -3).Format("20060102")     // 上周五
				actionDayNext = t.AddDate(0, 0, -2).Format("20060102") // 上周六
			} else {
				actionDay = t.AddDate(0, 0, -1).Format("20060102") // 上一天
				actionDayNext = tradingDay                         // 本日
			}

			startQuote()
		} else {
			logrus.Error("日期字段错误：", tradingDay)
		}
	}
}
